package com.xuecheng.media.service.jobhandler;


import com.xuecheng.base.utils.Mp4VideoUtil;
import com.xuecheng.media.model.po.MediaProcess;
import com.xuecheng.media.service.MediaFileService;
import com.xuecheng.media.service.MediaProcessService;
import com.xxl.job.core.context.XxlJobHelper;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;

/**
 * xxl-job处理视频
 */
@Component
@Slf4j
public class VideoTask {

    @Autowired
    private MediaProcessService mediaProcessService;
    @Autowired
    private MediaFileService mediaFileService;

    //ffmpeg的路径
    @Value("${videoprocess.ffmpegpath}")
    private String ffmpegpath;

    @XxlJob("videoJobHandler")
    public void task() throws InterruptedException {
        //1.从process中找待处理任务
        // 分片参数
        int shardIndex = XxlJobHelper.getShardIndex();//执行器的序号，从0开始
        int shardTotal = XxlJobHelper.getShardTotal();//执行器总数

        //确定cpu的核心数，即一次需要限制的次数
        int processors = Runtime.getRuntime().availableProcessors();
        //找到任务
        List<MediaProcess> tasks = mediaProcessService.findTasks(shardIndex,shardTotal,processors);
        log.info("cpu==>"+processors+"有执行器"+shardTotal+"个，"+shardIndex+"找到任务==>"+tasks);

        //开线程执行任务
        int taskSize=tasks.size();
        if(taskSize<=0){
            return;
        }
        //创建一个线程池
        ExecutorService executorService = Executors.newFixedThreadPool(taskSize);
        //使用的计数器
        CountDownLatch countDownLatch = new CountDownLatch(taskSize);

        for (MediaProcess mediaProcess : tasks) {
            executorService.execute(()->{
                try {
                    Long taskId=mediaProcess.getId();
                    String fileId=mediaProcess.getFileId();
                    String bucket = mediaProcess.getBucket();
                    String originMinioPath = mediaProcess.getFilePath();
                    //2.乐观锁，锁一个任务
                    Boolean b = mediaProcessService.updateStatusFroRun(mediaProcess);
                    if(!b){
                        log.info("抢任务失败"+mediaProcess.getId());
                        return;
                    }
                    //3.将Minio文件下载到本地
                    File downloadMinioFile = mediaFileService.downloadMinioFile(mediaProcess.getBucket(), mediaProcess.getFilePath());
                    //TODO：操作
                    String absolutePath = downloadMinioFile.getAbsolutePath();
                    String mp4Name=mediaProcess.getFileId()+".mp4";
                    File mp4 = File.createTempFile("minio", ".mp4");
                    //将minio的文件转为本地文件
                    Mp4VideoUtil mp4VideoUtil = new Mp4VideoUtil(ffmpegpath, absolutePath, mp4Name, mp4.getAbsolutePath());
                    //开始视频转换，成功将返回success,失败返回失败原因
                    String result = mp4VideoUtil.generateMp4();
                    if (!result.equals("success")) {
                        log.debug("视频转码失败");
                        mediaProcessService.saveProcessFinishStatus(taskId, "3", fileId, null, result);
                        return;

                    }
                    //mp4文件的url
                    String url = getFilePath(fileId, ".mp4");
                    //上传到minio
                    boolean b1 = mediaFileService.addMediaFilesToMinIO(mp4.getAbsolutePath(), "video/mp4", bucket, url);
                    if (!b1) {
                        log.debug("上传mp4到minio失败,taskid:{}", taskId);
                        mediaProcessService.saveProcessFinishStatus(taskId, "3", fileId, null, "上传mp4到minio失败");
                        return;
                    }
                    //删除minio原来文件
                    mediaFileService.deleteMinioFile(bucket,originMinioPath);
                    //更新任务状态为成功
                    mediaProcessService.saveProcessFinishStatus(taskId, "2", fileId, url, result);
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    //计算器减去1
                    countDownLatch.countDown();
                }
            });
        }
        //阻塞,指定最大限制的等待时间，阻塞最多等待一定的时间后就解除阻塞
        countDownLatch.await(30, TimeUnit.MINUTES);
    }
    private String getFilePath(String fileMd5,String fileExt){
        return   fileMd5.substring(0,1) + "/" + fileMd5.substring(1,2) + "/" + fileMd5 + "/" +fileMd5 +fileExt;
    }
}
